package vegal.hiray.com;

import android.support.v7.widget.RecyclerView;
import android.view.View;

import java.util.List;

/**
 * Created by hiray on 2018/1/24.
 *
 * @author hiray
 */

public class VegalLayoutManager extends RecyclerView.LayoutManager {


    private static final boolean DEBUG = BuildConfig.DEBUG;

    private static final int INVALID_OFFSET = Integer.MIN_VALUE;

    public static final int NO_POSITION = -1;

    public static final long NO_ID = -1;

    public static final int INVALID_TYPE = -1;

    public static final int HORIZONTAL = OrientationHelper.HORIZONTAL;

    public static final int VERTICAL = OrientationHelper.VERTICAL;

    private OrientationHelper mOrientationHelper;

    private LayoutState mLayoutState = new LayoutState();
    private RecyclerView.State mState;
    private AnchorInfo mAnchorInfo = new AnchorInfo();

    /**
     * Stashed to avoid allocation, currently only used in
     * {@link #fill(RecyclerView.Recycler, RecyclerView.State, int)} ())
     */
    private final LayoutChunkResult mLayoutChunkResult = new LayoutChunkResult();

    @Override
    public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
        if (state.getItemCount() == 0 && state.isPreLayout())
            return;
        ensureContractSizeAndEtc(recycler);
    }

    private void ensureContractSizeAndEtc(RecyclerView.Recycler recycler) {

    }

    @Override
    public RecyclerView.LayoutParams generateDefaultLayoutParams() {
        return new RecyclerView.LayoutParams(RecyclerView.LayoutParams.WRAP_CONTENT,
                RecyclerView.LayoutParams.WRAP_CONTENT);
    }

    @Override
    public boolean canScrollVertically() {
        return true;
    }

    @Override
    public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
        return super.scrollVerticallyBy(dy, recycler, state);
    }

    /**
     * save some layout info,such as scroll direction,
     * optimizing bullshit code
     */
    @Google
    private class LayoutState {
        static final int LAYOUT_START = -1;

        static final int LAYOUT_END = 1;

        static final int ITEM_DIRECTION_HEAD = -1;

        static final int ITEM_DIRECTION_TAIL = 1;
        /**
         * decide whether recycle or not(in scroll we set true,but false in layout pass where
         * we dep on children to determine sth
         */
        public boolean mRecycle = true;
        /**
         * views that we  use first
         */
        private List<RecyclerView.ViewHolder> mScrapList = null;
        /**
         * index we start in fetching view
         */
        private int mCurrentPosition = Integer.MAX_VALUE;
        /**
         * scroll offset this time
         */
        private int mOffset;

        /**
         * Number of pixels that we should fill, in the layout direction.
         */
        int mAvailable;

        /**
         * Used if you want to pre-layout items that are not yet visible.
         * The difference with {@link #mAvailable} is that, when recycling, distance laid out for
         * {@link #mExtra} is not considered to avoid recycling visible children.
         */
        int mExtra = 0;

        boolean mIsPreLayout;

        private int end = NO_POSITION;

        /**
         * Defines the direction in which the data adapter is traversed.
         * Should be {@link #ITEM_DIRECTION_HEAD} or {@link #ITEM_DIRECTION_TAIL}
         */
        int mItemDirection;

        /**
         * Defines the direction in which the layout is filled.
         * Should be {@link #LAYOUT_START} or {@link #LAYOUT_END}
         */
        int mLayoutDirection;

        /**
         * because this LayoutManager is kind of weird, items are stacked,
         * so it is a little tricky to calc the available distance when layouting views;
         * thus ,we decide to add complement to solve this problem
         */
        int complement;

        private View next(RecyclerView.Recycler recycler) {
            if (mScrapList != null)
                return nextFromScrapList();
            View view = recycler.getViewForPosition(mCurrentPosition);
            mCurrentPosition += mItemDirection;
            return view;
        }

        private View nextFromScrapList() {
            int size = mScrapList.size();
            for (int i = 0; i < size; i++) {
                View child = mScrapList.get(i).itemView;
                RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) child.getLayoutParams();
                if (lp.isItemRemoved())
                    continue;
                if (mCurrentPosition == lp.getViewLayoutPosition()) {
                    //update current position
                    assignPositionFromView(child);
                    return child;
                }

            }
            return null;
        }

        private void assignPositionFromView(View ignore) {
            final View closest = nextViewInLimitedList(ignore);
            if (closest == null) {
                mCurrentPosition = NO_POSITION;
            } else {
                mCurrentPosition = ((RecyclerView.LayoutParams) closest.getLayoutParams())
                        .getViewLayoutPosition();
            }
        }

        public View nextViewInLimitedList(View ignore) {
            int size = mScrapList.size();
            View closest = null;
            int closestDistance = Integer.MAX_VALUE;
            if (DEBUG && mIsPreLayout) {
                throw new IllegalStateException("Scrap list cannot be used in pre layout");
            }
            for (int i = 0; i < size; i++) {
                View view = mScrapList.get(i).itemView;
                final RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) view.getLayoutParams();
                if (view == ignore || lp.isItemRemoved()) {
                    continue;
                }
                final int distance = (lp.getViewLayoutPosition() - mCurrentPosition)
                        * mItemDirection;
                if (distance < 0) {
                    continue; // item is not in current direction
                }
                if (distance < closestDistance) {
                    closest = view;
                    closestDistance = distance;
                    if (distance == 0) {
                        break;
                    }
                }
            }
            return closest;
        }

        /**
         * @return true if there is no more element
         */
        public boolean hasMore(RecyclerView.State state) {
            return mCurrentPosition >= 0 && mCurrentPosition < state.getItemCount();
        }


//        /**
//         * compute the start and end position when layout view
//         */
//        private void prepareStartAndEnd() {
//            int curPos = mTotalOffset / mUnit;
//            int leavingSpace = getWidth() - (left(curPos) + mUnit);
//            int itemCountAfterBaseItem = leavingSpace / mUnit + 2;
//            int e = curPos + itemCountAfterBaseItem;
//            mCurrentPosition = curPos - maxStackCount >= 0 ? curPos - maxStackCount : 0;
//            end = e >= getItemCount() ? getItemCount() - 1 : e;
//        }
    }


    @Google
    class AnchorInfo {
        int mPosition;
        int mCoordinate;
        /**
         * 是否布局是从End开始，由reverseLayout和stackFromEnd决定，
         * 两者只要不同那么布局都是End开始
         */
        boolean mLayoutFromEnd;
        boolean mValid;

        AnchorInfo() {
            reset();
        }

        void reset() {
            mPosition = NO_POSITION;
            mCoordinate = INVALID_OFFSET;
            mLayoutFromEnd = false;
            mValid = false;
        }

        public void assignFromView(View child) {
            if (mLayoutFromEnd) {
                mCoordinate = mOrientationHelper.getDecoratedEnd(child)
                        + mOrientationHelper.getTotalSpaceChange();
            } else {
                mCoordinate = mOrientationHelper.getDecoratedStart(child);
            }

            mPosition = getPosition(child);
        }

        void assignCoordinateFromPadding() {
            mCoordinate = mLayoutFromEnd
                    ? mOrientationHelper.getEndAfterPadding()
                    : mOrientationHelper.getStartAfterPadding();
        }
    }

    @Google
    protected static class LayoutChunkResult {
        int mConsumed;
        boolean mFinished;
        boolean mIgnoreConsumed;
        boolean mFocusable;

        void resetInternal() {
            mConsumed = 0;
            mFinished = false;
            mIgnoreConsumed = false;
            mFocusable = false;
        }
    }
}
